// A partir de un formulario, generar los resultados y la ponderación.

// Rango difuso en el rango [0,10]
function rangoDifuso (x0,x1,x2,x3) {
	this.x = new Array(x0, x1, x2, x3);
};

// Para la inversion.
rangoDifuso.prototype.infinito = 10;

// this = this + other.
rangoDifuso.prototype.sumar = function(other) {
	for (var i=0; i<4; i++)
		this.x[i] += other.x[i];
};

// this = this - other
rangoDifuso.prototype.restar = function(other) {
	for (var i=0; i<4; i++)
		this.x[i] -= other.x[i];
};

// this = 1 / this
rangoDifuso.prototype.invertir = function() {
	// Efectivamente dejando el vector invertido y ordenado de menor a mayor.
	var aux = this.x[0];
	this.x[0] = 1.0/this.x[3];
	this.x[3] = 1.0/aux;
	aux = this.x[1];
	this.x[1] = 1.0/this.x[2];
	this.x[2] = 1.0/aux;

};

// this = escala * this
rangoDifuso.prototype.escalar = function(escala) {
	for (var i=0; i<4; i++)
		this.x[i] *= escala;
};

rangoDifuso.prototype.toString = function() {
	return "["+this.x.join(',')+"]";
};

rangoDifuso.prototype.toFixed = function(decimals) {
	var aux = new Array();
	for (var i=0; i<4; i++)
		aux[i] = this.x[i].toFixed(decimals);
	return aux;
};

rangoDifuso.prototype.pertenencia = function(value) {
	if ( (value > this.x[0]) && (value < this.x[3]) ) {
		if (value < this.x[1])
			// primer pendiente.
			return ( (value - this.x[0]) / (this.x[1]- this.x[0]) );

			return -1;		
		if (value < this.x[2])
			return 1.0;

		// segunda pendiente.
		return ( (value - this.x[3]) / (this.x[2]- this.x[3]) );
	}
	return 0.0;
}

/*
Factory-method: construye los rangos difusos a partir de un string que lo denomina.
	- difuse:
		nada	=   0,   0, 1.2, 2.2
		poco	= 1.2, 2.2, 3.4, 4.4
		regular	= 3.4, 4.4, 5.6, 6.6
		mucho	= 5.6, 6.6, 7.8, 8.8
		todo	= 7.8, 8.8,  10,  10

	- bool:
		si	=  10,  10,  10,  10
		no	=   0,   0,   0,   0
*/
function rangoFactory(nombre, opuesto, escala) {
	var value = undefined;

	// Bool	
	if (nombre === 'si')	
		value = (!opuesto) ? 101 : 100;
	if (nombre ==='no')
		value = (!opuesto) ? 100 : 101;

	// Difuse
	if (nombre ==='nada')
		value = (!opuesto) ? 1 : 5;
	if (nombre ==='poco')
		value = (!opuesto) ? 2 : 4;
	if (nombre ==='regular')
		value = 3;
	if (nombre ==='mucho')
		value = (!opuesto) ? 4 : 2;
	if (nombre ==='todo')
		value = (!opuesto) ? 5 : 1;

	var nuevo = undefined;

	if (value !== undefined) {
		// Difuse
		switch (value) {
			case (1):
				nuevo = new rangoDifuso(0.0, 0.0, 1.2, 2.2);
				break;
			case (2):				
				nuevo = new rangoDifuso(1.2, 2.2, 3.4, 4.4);
				break;
			case (3):
				nuevo = new rangoDifuso(3.4, 4.4, 5.6, 6.6);
				break;
			case (4):
				nuevo = new rangoDifuso(5.6, 6.6, 7.8, 8.8);
				break;
			case (5):
				nuevo = new rangoDifuso(7.8, 8.8,  10.0,  10.0);
				break;
		}

		// Bool
		switch (value) {
			case (101):
				nuevo = new rangoDifuso(10.0, 10.0, 10.0, 10.0);
				break;
			case (100):
				nuevo = new rangoDifuso( 0.0,  0.0,  0.0,  0.0);
				break;
		}
	} else {
		// int
		value = parseFloat(nombre);
		if (!isNaN(value) && isFinite(value) ) {
			if (opuesto)
				value *= -1.0;
			nuevo = new rangoDifuso( value, value, value, value);
		}
	}

	if (escala !== 1) 
		nuevo.escalar(escala);

	return (nuevo);
};

function tipos2rangos(tipos,pesos) {
	var rangos = new Array();

	for (var i=0; i<tipos.length; i++) {
		var p = pesos[i];
		var r = rangoFactory(tipos[i], (p<0),1);
		rangos.push(r);
	}
	return (rangos);
};

function mediaAritmetica(rangos, pesos) {
	var Ma = undefined;
	if ( (rangos.length === pesos.length) && (rangos.length > 0) ) {
		Ma = new rangoDifuso(0.0,0.0,0.0,0.0);
		var Sum_p = 0.0;
		for (var i=0; i<rangos.length; i++) {
			var r = new rangoDifuso(0.0,0.0,0.0,0.0);
			r.sumar(rangos[i]);
			var p = parseFloat(pesos[i]);
			
			// calculo el denominador y el divisor.
			r.escalar(Math.abs(p));
			Ma.sumar(r);
			Sum_p = Sum_p + Math.abs(p);
		}

		Ma.escalar(1.0/Sum_p);
	}
	return Ma;
};

function mediaGeometrica(rangos, pesos) {
	var Mg = undefined;
	if ( (rangos.length === pesos.length) && (rangos.length > 0) ) {
		Mg = new rangoDifuso(0.0,0.0,0.0,0.0);
		Sum_p = 0.0;
		for (var i=0; i<rangos.length; i++) {
			var r = new rangoDifuso(0.0,0.0,0.0,0.0);
			r.sumar(rangos[i]);
			var p = parseFloat(pesos[i]);

			// calculo el denominador y el divisor.
			r.invertir();
			r.escalar(Math.abs(p));
			Mg.sumar(r);
			Sum_p = Sum_p + Math.abs(p);


		}
		Mg.invertir();
		Mg.escalar(Sum_p);
	}
	return Mg;
};

function puntajeEstandard(rangos,pesos) {
	var Ma = mediaAritmetica(rangos,pesos);
	var Mg = mediaGeometrica(rangos,pesos);

	var resultado = new rangoDifuso(0.0,0.0,0.0,0.0);

	resultado.sumar(Ma);
	resultado.sumar(Mg);
	resultado.escalar(0.5);

//	for (var i=0; i<4; i++)
//		if (resultado.x[i] < 0.0)
//			resultado.x[i] = 0.0;
//		if (resultado.x[i] >10.0)
//			resultado.x[i] = 10.0;		

	return ( resultado );
};

function caracteristica(htmlElement) {
	// Selecciono los input que tengan nombre coincidente con la expresion regular "dimension".
	if ( (htmlElement.type === 'select-one') || (htmlElement.type === 'number') ) {
		var peso = parseFloat( htmlElement.getAttribute('peso') );
		var umbral = htmlElement.getAttribute('umbral');
		var naturaleza = htmlElement.getAttribute('naturaleza');
		var tipo = undefined;
		var valido = true;
		var dimension = htmlElement.getAttribute('name');
		if (htmlElement.type === 'select-one') {
			tipo = htmlElement.options[ htmlElement.selectedIndex ].value;

			if ( (umbral !== undefined) && (umbral !== '') ) {
				if ( (naturaleza === 'bool') && (tipo !== umbral) ) {
//						console.log(htmlElement.getAttribute('name')+"["+tipo+"!="+umbral+"] : no supera el umbral.");
						valido = false;
				}

				if (naturaleza === 'difuse') {						
					umbralpos = undefined;
					for (var j=0; j<htmlElement.options.length; j++) {
						if (htmlElement.options[j].value === umbral) {
							umbralpos = j;
							break;
						}
					}

					if (htmlElement.selectedIndex < umbralpos) {
//						console.log(htmlElement.getAttribute('name')+"["+tipo+"<"+umbral+"] : no supera el umbral.");
						valido = false;
					}
				}
			}
		} else {
			if (naturaleza === 'int') {
				if (htmlElement.value !== '')
					tipo = parseFloat(htmlElement.value);
				else
					tipo = 0.0;
			
				if ( parseFloat(htmlElement.min) > parseFloat(htmlElement.value) )
					valido = false;
				if ( parseFloat(htmlElement.max) < parseFloat(htmlElement.value) )
					valido = false;
				if ( (umbral !== undefined) && (tipo < umbral) ) {
//					console.log(htmlElement.getAttribute('name')+"["+tipo+"<"+umbral+"] : no supera el umbral.");
					valido = false;
				}
			}
			else
				tipo = htmlElement.getAttribute('value');
		}
			

		if (peso === undefined)
			peso = 1;
	}

	var resultado = new Object();
	resultado.peso = peso;
	resultado.umbral = umbral;
	resultado.naturaleza = naturaleza;
	resultado.tipo = tipo;
	resultado.valido = valido;
	resultado.dimension = dimension;

	return resultado;
} 

function puntajeEstandardForm(dimension,id) {
	var f = document.forms[0];
	
	var tipos = [];
	var pesos = [];
	var regexp = new RegExp(dimension);

	f.isValid = true;
	for (var i=0; i<f.length; i++) {
		if (regexp.test(f[i].name)) {
			partes = caracteristica(f[i]);
			
			tipos.push(partes.tipo);
			pesos.push(partes.peso);			

			if (!partes.valido)
				f.isValid = false;
		}
	}

	var rangos = tipos2rangos(tipos,pesos);
	var resultado = puntajeEstandard(rangos,pesos);

	if (id !== undefined) {
		var grafico = document.getElementById('svg'+id);
	
		var li = document.getElementById('li'+id);
		if ( (grafico) && (li) ) {
			try {
				li.removeChild( grafico );
			} catch (e) {
				console.log(e);
			}
		}
	
		var grafico = puntajeSVG(resultado,'svg'+id,'svg'+id);
		li.appendChild(grafico.getElement());
	}

	return ( resultado );
};

function puntajeEstandardFormTotal() {
	var p = puntajeEstandardForm('P[0-9]+');
	var a = puntajeEstandardForm('A[0-9]+');
	var j = puntajeEstandardForm('J[0-9]+');
	var e = puntajeEstandardForm('E[0-9]+');

	//para: (p,a,j,e);
	var pesos = new Array(8,8,3,5);
	var puntajes = new Array(p,a,j,e);
	var total = mediaGeometrica( puntajes,pesos );

	var buttons = document.getElementsByTagName('button');
	var regexp = new RegExp('button[PAJE]');
	for (var i=0; i<buttons.length; i++) {
		var x = buttons[i];
		if (regexp.test(x.name)) {
			x.click();
		}
	}

	var grafico = document.getElementById('svgT');
	var li = document.getElementById('liT');
	if ( (grafico) && (li) ) {
		try {
			li.removeChild( grafico );
		} catch (e) {
			console.log(e);
		}
	}
	
	var grafico = puntajeSVG(total,'svgT','svgT');
	li.appendChild(grafico.getElement());
	return ( total );
};

function puntajeSVG( rango , name, id) {
	var fixed = rango.toFixed(2);
	
	var svg = new svgCanvas(name,id,20,150);
	var pertenencia = "stroke:purple;stroke-width:0.1px;fill:none;";
	var grilla = "stroke:slategray;stroke-width:0.05px;fill:none;";
	var minimo = "stroke:black;stroke-width:0.1px;fill:none;";
	var mal = "stroke:red;stroke-width:0.1px;fill:none;";
	var bien = "stroke:blue;stroke-width:0.1px;fill:none;";
//	svg.getElement().setAttribute('style','border:1px solid green;float:right;');
	svg.getElement().setAttribute('viewBox','-0.5 -0.5 11 0.01');

	var media = ( (rango.x[1] + rango.x[2])*0.5 ).toFixed(2);
	var viabilidad = 1.0;
	if (rango.x[1] < 6.0)
		viabilidad = rango.pertenencia(6.0);
	
	for (var i=0; i<fixed.length; i++)
		if (fixed[i] < 0)
			fixed[i] = 0;

	var points = [0,0];
	if (fixed[0] > 0.0) {
		points.push(fixed[0]);
		points.push(0);
	}
	points.push(fixed[1]);
	points.push(-1);
	points.push(fixed[2]);
	points.push(-1);
	points.push(fixed[3]);
	points.push(0);
	if (fixed[3] < 10.0) {
		points.push(10.0);
		points.push(0);
	}

	// Linea de pertenencia = 1;
	svg.appendChild( new line(-1,-1,12,-1,grilla) );
	// Linea de pertenencia = 0;
	svg.appendChild( new line(-1,0,12,0,grilla) );

	for (var i=0; i<11; i++) {
		if (i !== 6)
			svg.appendChild( new line(i,-2,i,2,grilla) );
		else
			svg.appendChild( new line(i,-2,i,2,minimo) );
	}	

	var pertenencia = mal;
	if (viabilidad === 1.0)
		pertenencia = bien;
	var pl = new polyline(points, pertenencia);
	svg.appendChild(pl);

	return (svg);
};

function addClass(e, clase) {
	var pos = e.className.indexOf(clase);

	if (pos === -1)
		e.className = e.className + ' ' + clase;
	return (pos === -1);
}

function removeClass(e, clase) {
	var pos = e.className.indexOf(clase);
	e.className = e.className.replace(' '+clase,'');
	
	return (pos !== -1);
}

function checkInput (e) {
	var c = caracteristica(e);

	if (c.dimension !== undefined) {
		htmle = document.getElementById(c.dimension);

		var cambio = false;
		if (c.valido)
			cambio = removeClass(e,'invalido');
		else
			cambio = addClass(e,'invalido');

		if (cambio)
			updateDetailClass(htmle.parentNode.parentNode.parentNode.parentNode.parentNode);

		return c.valido;
	}
	
	return undefined;
}

function updateDetailClass(d) {
	var valido = (d.className.indexOf('invalido') === -1);

	var inputs = d.getElementsByTagName('input');
	var inputValido = true;
	for (var i=0; i<inputs.length; i++) {
		if (inputs[i].className.indexOf('invalido') !== -1)
			inputValido = false;
	}
	
	var inputs = d.getElementsByTagName('select');
	for (var i=0; i<inputs.length; i++) {
		if (inputs[i].className.indexOf('invalido') !== -1)
			inputValido = false;
	}

	if (valido !== inputValido) {
		if (inputValido)
			removeClass(d,'invalido');
		else
			addClass(d,'invalido');
	}
}

function onLoadForm(f) {
	var valido = true;
	if (valido) {
		var inputs = document.getElementsByTagName('input');
		var inputValido = false;
		for (var i=0; i<inputs.length; i++) {
			inputValido = checkInput(inputs[i]);
			if (inputValido !== undefined)
				valido = inputValido && valido;
		}
		
		var inputs = document.getElementsByTagName('select');
		for (var i=0; i<inputs.length; i++) {
			inputValido = checkInput(inputs[i]);
			if (inputValido !== undefined)
				valido = inputValido && valido;
		}
	}
	return valido;
}

function submitCheck(f) {
	var valido = true;

	var details = document.getElementsByTagName('details');
	for (var i=0; i<details.length; i++) {
		if (details[i].className.indexOf('invalido') !== -1)
			valido = false;
	}

	if (!valido)
		alert('La encuesta tiene parametros necesarios inviables.');
	
	return false; // TODO ARREGLAR EL SUBMIT.
//	return valido;
}

